/*
 * ENUM Discoverer. ENUM Demonstration software, demonstrating the potential of ENUM.
 * 
 * Copyright (C) 2009 SIDN and ISOC.nl
 * 
 * This file is part of ENUM Discoverer.
 *
 * ENUM Discoverer is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * ENUM Discoverer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with ENUM Discoverer.  If not, see <http://www.gnu.org/licenses/>.
 */

package nl.sidn.enumdiscoverer.startup;

import nl.sidn.enumdiscoverer.LogConfig;
import nl.sidn.enumdiscoverer.R;
import nl.sidn.enumdiscoverer.callhandling.CallBroadcastReceiver;
import nl.sidn.enumdiscoverer.sync.EnumSyncService;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.provider.Contacts.Groups;
import android.text.format.DateUtils;
import android.util.Log;

/**
 * Contains methods for starting up the applications
 * @author	Grant Patterson (grant.patterson@catalyst.net.nz)
 */
public class StartupHelper {

	static final String TAG = LogConfig.getLogTag(StartupHelper.class);
	// whether DEBUG level logging is enabled (whether globally, or explicitly for this log tag)
	static final boolean DEBUG = LogConfig.isDebug(TAG);
	// whether VERBOSE level logging is enabled
	static final boolean VERBOSE = LogConfig.VERBOSE;
	
	
	// time before the first ENUM sync run (from when the activity starts)
	private static final long INITIAL_SYNC_DELAY = 60000;  // 1 minute
	private static final long INTERVAL_UNDEFINED = Long.MIN_VALUE;
	
	
	/**
	 * Initialises the application environment
	 * @param context
	 */
	public static void initEnvironment(Context context) {
		
		// The application depends on the existence of a "My Contacts" group in Contacts.
		// This isn't provided by default in Android 2.0, and it is possible for it to not
		// exist in earlier versions (e.g. if something has gone wrong in setting up the phone's Google
		// Account.
		// As a workaround, we create the group if it doesn't exist
		ensureMyContactsGroupExists(context);
		
		// ensure we have default preferences (if none set by user)
		PreferenceManager.setDefaultValues(context, R.xml.preferences, false);
	}
	
	/**
	 * Checks whether the ENUM in-call screen is enabled in preferences.
	 * @param context
	 * @return true if the ENUM in-call screen is enabled in preferences, otherwise false.
	 */
	public static boolean isInCallScreenEnabled(Context context) {
		
		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
		String key = context.getString(R.string.pref_incall_switch_key);
		
		return prefs.getBoolean(key, false);
	}
	
	public static void enableIncallScreen(Context context, boolean enable) {
		
		enableCallBroadcastReceiver(context, enable);
	}
	
	public static void initIncallScreen(Context context) {
		
		enableIncallScreen(context, isInCallScreenEnabled(context));
	}
	
	public static void enableCallBroadcastReceiver(Context context, boolean enable) {
		
		PackageManager packMan = (PackageManager)context.getPackageManager();
		
		ComponentName name = new ComponentName(context, CallBroadcastReceiver.class);
		
		int state = enable ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
			PackageManager.COMPONENT_ENABLED_STATE_DISABLED; 
		packMan.setComponentEnabledSetting(name, state, PackageManager.DONT_KILL_APP);
	}
	
	/**
	 * Checks whether the ENUM Sync has been enabled in preferences
	 * @param context
	 * @return true if ENUM Sync has been enabled in preferences
	 */
	public static boolean isSyncEnabled(Context context) {
		
		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
		String key = context.getString(R.string.pref_enumsync_switch_key);
		
		return prefs.getBoolean(key, false);
	}
	
	/**
	 * Resets the scheduling of EnumSyncService. The service will be scheduled for recurring
	 * runs with the interval set in preferences. The first run is 1 minute after this method
	 * is called.
	 * @param context The Context to use
	 */
	public static void resetSyncScheduling(Context context) {
		
		long syncInterval = readIntervalPref(context);
		
		if (syncInterval == INTERVAL_UNDEFINED) {
			Log.w(TAG, "No ENUM sync interval defined. ENUM sync will not be scheduled");
			return;
		}
		
		AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
		
		// use time since boot rather than wall clock time. If phone is asleep, then wait until awake
		int type = AlarmManager.ELAPSED_REALTIME;
		long startTime = SystemClock.elapsedRealtime() + INITIAL_SYNC_DELAY;
		
		Intent intent = new Intent(context, EnumSyncService.class);
		PendingIntent operation = PendingIntent.getService(context.getApplicationContext(), 0, intent, 0);
		
		// cancel any ENUM sync runs we already had scheduled
		alarmManager.cancel(operation);
		
		// we don't need to sync at exact time. Let the phone save power if it can
		alarmManager.setInexactRepeating(type, startTime, syncInterval, operation);
		if (DEBUG) Log.d(TAG, "EnumSyncService scheduled for every " + syncInterval + " milliseconds");
	}
	
	public static void initSyncService(Context context) {
		
		if (isSyncEnabled(context)) {
			resetSyncScheduling(context);
		}
	}
	
	private static long readIntervalPref(Context context) {
		
		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
		String syncKey = context.getString(R.string.pref_enumsync_interval_key);
		
		// sync interval stored as hours
		String hoursStr = prefs.getString(syncKey, null);
		if (hoursStr == null) {
			return INTERVAL_UNDEFINED;
		}
		float hours = Float.parseFloat(hoursStr);
		
		// return the sync interval in milliseconds
		return Math.round(hours * DateUtils.HOUR_IN_MILLIS);
	}
	
	/**
	 * Cancels any previously scheduled EnumSyncService runs in the AlarmManager
	 * @param context The Context to use
	 */
	public static void cancelEnumSync(Context context) {
		
		AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
		
		Intent intent = new Intent(context, EnumSyncService.class);
		PendingIntent operation = PendingIntent.getService(context.getApplicationContext(), 0, intent, 0);
		
		alarmManager.cancel(operation);
		if (DEBUG) Log.d(TAG, "EnumSyncService cancelled");
	}
	
	private static void ensureMyContactsGroupExists(Context context) {
		
		ContentResolver resolver = context.getContentResolver();
		
		if (myContactsGroupExists(resolver)) {
			// nothing to do
			return;
		}
		
		// create "My Contacts" group
		
		Log.i(TAG, "\"My Contacts\" group not found. Creating...");
		
		ContentValues values = new ContentValues();
		values.put(Groups.NAME, Groups.GROUP_MY_CONTACTS);
		values.put(Groups.SYSTEM_ID, Groups.GROUP_MY_CONTACTS);
		
		resolver.insert(Groups.CONTENT_URI, values);
	}
	
	private static boolean myContactsGroupExists(ContentResolver resolver) {
		
		String [] projection = {Groups._ID};
		
		Cursor cursor = resolver.query(Groups.CONTENT_URI, projection,
				Groups.SYSTEM_ID + "='" + Groups.GROUP_MY_CONTACTS + "'", null, null);
		
		if (cursor != null) {
			try {
				if (cursor.moveToFirst()) {
					return true;
				}
			} finally {
				cursor.close();
			}
		}
		
		return false;
	}
}
